--- Test properties of the 'Json' module
module tests.qc.JSON where

import frege.Prelude hiding(Object)

import Data.JSON as Json(Value, runParser, parseValue, lexer, parseJSON, toJSON, fromJSON)
import Test.QuickCheck as Q public

instance Arbitrary Value where
    arbitrary = frequency [
                        (5,  return Null),
                        (6,  Bool   <$> arbitrary),
                        (42, String <$> arbitrary),
                        (6,  Number . Double.show  <$> arbitrary),
                        (6,  Number . Float.show   <$> arbitrary),
                        (6,  Number . Integer.show <$> arbitrary),
                        (6,  Number . Int.show     <$> arbitrary),
                        (6,  Number . Long.show    <$> arbitrary),
                        (6,  Number . Short.show   <$> arbitrary),
                        -- doesn't work because @show (byte 0) == "0x00"@
                        -- (5,  Number . Byte.show    <$> arbitrary),
                        (1,  Array  <$> arbitrary),
                        (1,  Struct <$> arbitrary),
                    ]


--- parsing the 'String' representation of any 'Value' yields the same 'Value'
p_value = property $ \(a::Value) -> let 
            json = show a
            len  = length json `quot` 100
            coll = "json text length %d00..%d00".format len (len+1) :: String
        in collect coll (runParser parseValue (lexer json) == Right a)

--- JSON round trip
fromTo ∷ (Json.ToJSON 𝖇,Json.FromJSON 𝖇) ⇒ 𝖇 → Either String 𝖇
fromTo = fromJSON . toJSON

--- parsing the JSON representation of some value yields the same value
checkFromTo ∷ (Json.ToJSON 𝖆,Json.FromJSON 𝖆,Eq 𝖆) ⇒ 𝖆 → Bool
checkFromTo x = fromTo x == Right x

p_roundUnit     = once      (checkFromTo ∷ ()               → Bool)
p_roundBool     = property  (checkFromTo ∷ Bool             → Bool)
p_roundChar     = property  (checkFromTo ∷ Char             → Bool)
p_roundInt      = property  (checkFromTo ∷ Int              → Bool)
p_roundLong     = property  (checkFromTo ∷ Long             → Bool)
p_roundInteger  = property  (checkFromTo ∷ Integer          → Bool)
p_roundFloat    = property  (checkFromTo ∷ Float            → Bool)
p_roundDouble   = property  (checkFromTo ∷ Double           → Bool)
p_roundString   = property  (checkFromTo ∷ String           → Bool)
p_roundList     = property  (checkFromTo ∷ [String]         → Bool)
p_roundMaybe    = property  (checkFromTo ∷ Maybe [Char]     → Bool)
p_roundTuple    = property  (checkFromTo ∷ (String, Double) → Bool)


main [s] = println $ do
    runParser parseValue (lexer s)
main _ = return ()